home *** CD-ROM | disk | FTP | other *** search
- /*------------------------------------------------------------------------------
- #
- # TV-Man.c
- #
- # Copyright © Apple Computer, Inc. 1989-1990
- # All rights reserved.
- #
- #
- # This file contains the functions necessary to control the TV-Man application.
- # TV-Man has the ability to display various patterns on the screen. The ability to
- # generate sounds has been provided as well.
- #
- # In order to have an evironment which predictable events happen several definitions
- # must be established. The most critical is in the file architecture. Each functional
- # block will have its own source and header file. The main project file, in this
- # case TV-Man, will have its header file included with all other files. This will
- # allow for global constants. The utility source file shall contain functions that
- # are general purpose in nature and that can be used by all other functions. These
- # are intended not to be application or major block specific. In order for this to be
- # accomodated all functions in the utility source file must use only the information
- # that is passed to them or information that can be gleaned from the system via
- # toolbox calls. There will be no header file associated with the utility file as this
- # will destroy the intent of the utilities.
- #
- # There are several files which contain information which is global in nature .These
- # file are included in the main project header file. They are: x.Errors.h, x.Ext.h,
- # x.Protos.h, x.Menus.h. The reason for containing them in seperate files is one of
- # convienience and accesability.
- #
- # Revision Log:
- #
- # 11-05-91 RGK Added the menu items for single color screens
- # 04-26-91 RGK Creation
- #
- #
- ------------------------------------------------------------------------------*/
-
- /* This is a list of all local includes necessary for this program. */
-
- #include "TV-Man.h"
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* The following lists the globals used in this program. The "g" prefix is
- used to emphasize that a variable is global.
-
- GMac is used to hold the result of a SysEnvirons call. This makes
- it convenient for any routine to check the environment. */
-
- SysEnvRec gMac; /* set up by Initialize */
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* GHasWaitNextEvent is set at startup, and tells whether the WaitNextEvent
- trap is available. If it is false, we know that we must call GetNextEvent. */
-
- Boolean gHasWaitNextEvent; /* set up by Initialize */
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* GInBackground is maintained by our osEvent handling routines. Any part of
- the program can check it to find out if it is currently in the background. */
-
- Boolean gInBackground; /* maintained by Initialize and DoEvent */
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* This is the number which identifies whch video pattern we will and have displayed */
-
- short gVideoPattern;
- short gLastVideoPattern;
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* This routine is part of the MPW runtime library. This external
- reference to it is done so that we can unload its segment, %A5Init. */
-
- extern void _DataInit();
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Segmentation strategy:
-
- This program consists of three segments. Main contains most of the code,
- including the MPW libraries, and the main program. Initialize contains
- code that is only used once, during startup, and can be unloaded after the
- program starts. %A5Init is automatically created by the Linker to initialize
- globals for the MPW libraries and is unloaded right away. Each file of C code will
- have a statement at the beginning which will identify the code segment it resides in. */
-
- #pragma segment Main
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Now we will start the code */
-
- main()
- {
- UnloadSeg((Ptr) _DataInit); /* note that _DataInit must not be in Main! */
- MaxApplZone(); /* expand the heap so code segments load at the top */
- Initialize(); /* initialize the program */
- UnloadSeg((Ptr) Initialize); /* note that Initialize must not be in Main! */
- SoundInit(); /* initalize the sound globals */
- EventLoop(); /* call the main event loop */
- }
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Get events forever, and handle them by calling DoEvent.
- Get the events by calling WaitNextEvent, if it's available, otherwise
- by calling GetNextEvent. Also call AdjustCursor each time through the loop. */
-
- void EventLoop()
- {
- RgnHandle cursorRgn;
- Boolean gotEvent;
- EventRecord event;
- Point mouse;
-
- cursorRgn = NewRgn(); /* we’ll pass WNE an empty region the 1st time thru */
- do
- {
- if ( gHasWaitNextEvent )
- {
- GetGlobalMouse(&mouse);
- AdjustCursor(mouse, cursorRgn);
- gotEvent = WaitNextEvent(everyEvent, &event, MAXLONG, cursorRgn);
- }
- else
- {
- SystemTask();
- gotEvent = GetNextEvent(everyEvent, &event);
- }
- if ( gotEvent )
- {
- /* make sure we have the right cursor before handling the event */
- AdjustCursor(event.where, cursorRgn);
- DoEvent(&event);
- }
- SoundCheck(); /* process any sound event necessary */
- }
- while ( true ); /* loop forever; we quit via ExitToShell */
- } /*EventLoop*/
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Do the right thing for an event. Determine what kind of event it is, and call
- the appropriate routines. */
-
- void DoEvent(event)
- EventRecord *event;
- {
- short part, err;
- WindowPtr window;
- Boolean hit;
- char key;
- Point aPoint;
-
- switch ( event->what )
- {
- case mouseDown:
- part = FindWindow(event->where, &window);
- switch ( part )
- {
- case inMenuBar: /* process a mouse menu command (if any) */
- AdjustMenus();
- DoMenuCommand(MenuSelect(event->where));
- break;
-
- case inSysWindow: /* let the system handle the mouseDown */
- SystemClick(event, window);
- break;
-
- case inContent:
- if ( window != FrontWindow() ) SelectWindow(window);
- break;
-
- case inDrag: /* pass screenBits.bounds to get all gDevices */
- DragWindow(window, event->where, &qd.screenBits.bounds);
- break;
-
- case inGrow:
- break;
-
- case inZoomIn:
- case inZoomOut:
- hit = TrackBox(window, event->where, part);
- if ( hit )
- {
- SetPort(window); /* the window must be the current port... */
- EraseRect(&window->portRect); /* because of a bug in ZoomWindow */
- ZoomWindow(window, part, true); /* note that we invalidate and erase... */
- InvalRect(&window->portRect); /* to make things look better on-screen */
- }
- break;
- }
- break;
-
- case keyDown:
- case autoKey:
- key = event->message & charCodeMask;
- if ( event->modifiers & cmdKey ) /* Command key down */
- if ( event->what == keyDown )
- {
- AdjustMenus();
- DoMenuCommand(MenuKey(key));
- }
- break;
-
- case activateEvt:
- DoActivate((WindowPtr) event->message, (event->modifiers & activeFlag) != 0);
- break;
-
- case updateEvt:
- DoUpdate((WindowPtr) event->message);
- break;
-
- case diskEvt:
- /* It is not a bad idea to at least call DIBadMount in response
- to a diskEvt, so that the user can format a floppy. */
- if ( HiWord(event->message) != noErr )
- {
- SetPt(&aPoint, kDILeft, kDITop);
- err = DIBadMount(aPoint, event->message);
- }
- break;
-
- case kOSEvent:
- switch ((event->message >> 24) & 0x0FF) /* must BitAND with 0x0FF to get only low byte */
- {
- case kSuspendResumeMessage: /* suspend/resume is also an activate/deactivate */
- gInBackground = (event->message & kResumeMask) == 0;
- DoActivate(FrontWindow(), !gInBackground);
- break;
- }
- break;
- }
- } /* DoEvent */
-
-
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Enable and disable menus based on the current state.
- The user can only select enabled menu items. We set up all the menu items
- before calling MenuSelect or MenuKey, since these are the only times that
- a menu item can be selected. Note that MenuSelect is also the only time
- the user will see menu items. This approach to deciding what enable/
- disable state a menu item has the advantage of concentrating all
- the decision-making in one routine, as opposed to being spread throughout
- the application. */
-
- void AdjustMenus()
- {
- WindowPtr window;
- MenuHandle menu;
-
- window = FrontWindow();
-
- menu = GetMHandle(mFile);
- if ( IsDAWindow(window) ) /* we can allow desk accessories to be closed from the menu */
- EnableItem(menu, iClose);
- else
- DisableItem(menu, iClose); /* but not this application */
-
- menu = GetMHandle(mEdit);
- if ( IsDAWindow(window) )
- { /* a desk accessory might need the edit menu… */
- EnableItem(menu, iUndo);
- EnableItem(menu, iCut);
- EnableItem(menu, iCopy);
- EnableItem(menu, iClear);
- EnableItem(menu, iPaste);
- }
- else
- { /* …but we don’t use it */
- DisableItem(menu, iUndo);
- DisableItem(menu, iCut);
- DisableItem(menu, iCopy);
- DisableItem(menu, iClear);
- DisableItem(menu, iPaste);
- }
-
- menu = GetMHandle(mPatterns);
- if ( IsAppWindow(window) )
- {
- EnableItem(menu, iTestPattern);
- EnableItem(menu, iColorBars);
- EnableItem(menu, iGrayScaleLD);
- EnableItem(menu, iGrayScaleDL);
- EnableItem(menu, iVLines);
- EnableItem(menu, iHLines);
- EnableItem(menu, iLBurst);
- EnableItem(menu, iRedScreen);
- EnableItem(menu, iGreenScreen);
- EnableItem(menu, iBlueScreen);
- EnableItem(menu, iWhiteScreen);
- }
- else
- {
- DisableItem(menu, iTestPattern);
- DisableItem(menu, iColorBars);
- DisableItem(menu, iGrayScaleLD);
- DisableItem(menu, iGrayScaleDL);
- DisableItem(menu, iVLines);
- DisableItem(menu, iHLines);
- DisableItem(menu, iLBurst);
- DisableItem(menu, iRedScreen);
- DisableItem(menu, iGreenScreen);
- DisableItem(menu, iBlueScreen);
- DisableItem(menu, iWhiteScreen);
- }
-
- /* first clear all the test checkmarks */
- CheckItem(menu, iTestPattern, false);
- CheckItem(menu, iColorBars, false);
- CheckItem(menu, iGrayScaleLD, false);
- CheckItem(menu, iGrayScaleDL, false);
- CheckItem(menu, iVLines, false);
- CheckItem(menu, iHLines, false);
- CheckItem(menu, iLBurst, false);
- CheckItem(menu, iRedScreen, false);
- CheckItem(menu, iGreenScreen, false);
- CheckItem(menu, iBlueScreen, false);
- CheckItem(menu, iWhiteScreen, false);
-
- /* Now set the correct check mark */
- CheckItem(menu, gVideoPattern, true);
-
- menu = GetMHandle(mBeeps);
- if ( IsAppWindow(window) )
- {
- EnableItem(menu, iBMSoprano);
- EnableItem(menu, iBMAlto);
- EnableItem(menu, iBMTenor);
- EnableItem(menu, iBMBass);
- EnableItem(menu, iBeepD);
- EnableItem(menu, iBeepE);
- }
- else
- {
- DisableItem(menu, iBMSoprano);
- DisableItem(menu, iBMAlto);
- DisableItem(menu, iBMTenor);
- DisableItem(menu, iBMBass);
- DisableItem(menu, iBeepD);
- DisableItem(menu, iBeepE);
- }
- } /* AdjustMenus */
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* This is called when an item is chosen from the menu bar (after calling
- MenuSelect or MenuKey). It performs the right operation for each command.
- It is good to have both the result of MenuSelect and MenuKey go to
- one routine like this to keep everything organized. */
-
- void DoMenuCommand(menuResult)
- long menuResult;
- {
- short menuID; /* the resource ID of the selected menu */
- short menuItem; /* the item number of the selected menu */
- short itemHit;
- Str255 daName;
- short daRefNum;
- Boolean handledByDA;
- WindowPtr window;
-
- window = FrontWindow(); /* there is only one window so get it */
- menuID = HiWord(menuResult); /* use macros for efficiency to... */
- menuItem = LoWord(menuResult); /* get menu item number and menu number */
- switch ( menuID )
- {
- case mApple:
- switch ( menuItem )
- {
- case iAbout: /* bring up alert for About */
- itemHit = Alert(rAboutAlert, nil);
- break;
-
- default: /* all non-About items in this menu are DAs */
- GetItem(GetMHandle(mApple), menuItem, daName);
- daRefNum = OpenDeskAcc(daName);
- break;
- }
- break;
-
- case mFile:
- switch ( menuItem )
- {
- case iClose:
- DoCloseWindow(FrontWindow());
- break;
-
- case iQuit:
- Terminate();
- break;
- }
- break;
-
- case mEdit: /* call SystemEdit for DA editing & MultiFinder */
- handledByDA = SystemEdit(menuItem-1); /* since we don’t do any Editing */
- break;
-
- case mPatterns:
- gLastVideoPattern = gVideoPattern; /* save the current Pattern */
- switch ( menuItem )
- {
- case iTestPattern:
- gVideoPattern = iTestPattern;
- break;
-
- case iColorBars:
- gVideoPattern = iColorBars;
- break;
-
- case iGrayScaleLD:
- gVideoPattern = iGrayScaleLD;
- break;
-
- case iGrayScaleDL:
- gVideoPattern = iGrayScaleDL;
- break;
-
- case iVLines:
- gVideoPattern = iVLines;
- break;
-
- case iHLines:
- gVideoPattern = iHLines;
- break;
-
- case iLBurst:
- gVideoPattern = iLBurst;
- break;
-
- case iRedScreen:
- gVideoPattern = iRedScreen;
- break;
-
- case iGreenScreen:
- gVideoPattern = iGreenScreen;
- break;
-
- case iBlueScreen:
- gVideoPattern = iBlueScreen;
- break;
-
- case iWhiteScreen:
- gVideoPattern = iWhiteScreen;
- break;
- }
- InvalRect(&window->portRect); /* invalidate the area to force an update */
- break;
-
- case mBeeps:
- switch ( menuItem )
- {
- case iBMSoprano:
- SopranoControls();
- break;
-
- case iBMAlto:
- AltoControls();
- break;
-
- case iBMTenor:
- TenorControls();
- break;
-
- case iBMBass:
- BassControls();
- break;
-
- case iBeepD:
- ClearAllSounds();
- KillSoundChannels();
- break;
-
- case iBeepE:
- SetAllSounds();
- break;
-
- }
- break;
- }
- HiliteMenu(0); /* unhighlight what MenuSelect (or MenuKey) hilited */
- } /* DoMenuCommand */
-
-
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Change the cursor's shape, depending on its position. This also calculates the region
- where the current cursor resides (for WaitNextEvent). If the mouse is ever outside of
- that region, an event would be generated, causing this routine to be called,
- allowing us to change the region to the region the mouse is currently in. If
- there is more to the event than just “the mouse moved”, we get called before the
- event is processed to make sure the cursor is the right one. In any (ahem) event,
- this is called again before we fall back into WNE. */
-
- void AdjustCursor(mouse,region)
- Point mouse;
- RgnHandle region;
- {
- WindowPtr window;
- RgnHandle arrowRgn;
- RgnHandle plusRgn;
- Rect globalPortRect;
-
- window = FrontWindow(); /* we only adjust the cursor when we are in front */
- if ( (! gInBackground) && (! IsDAWindow(window)) )
- {
- arrowRgn = NewRgn(); /* calculate regions for different cursor shapes */
- plusRgn = NewRgn();
-
- /* start with a big, big rectangular region */
- SetRectRgn(arrowRgn, kExtremeNeg, kExtremeNeg, kExtremePos, kExtremePos);
-
- if ( IsAppWindow(window) ) /* calculate plusRgn */
- {
- SetPort(window); /* make a global version of the viewRect */
- SetOrigin(-window->portBits.bounds.left, -window->portBits.bounds.top);
- globalPortRect = window->portRect;
- RectRgn(plusRgn, &globalPortRect);
- SectRgn(plusRgn, window->visRgn, plusRgn);
- SetOrigin(0, 0);
- }
-
- DiffRgn(arrowRgn, plusRgn, arrowRgn); /* subtract other regions from arrowRgn */
-
- if ( PtInRgn(mouse, plusRgn) ) /* change the cursor and the region parameter */
- {
- SetCursor(*GetCursor(plusCursor));
- CopyRgn(plusRgn, region);
- }
- else
- {
- SetCursor(&qd.arrow);
- CopyRgn(arrowRgn, region);
- }
-
- DisposeRgn(arrowRgn); /* get rid of our local regions */
- DisposeRgn(plusRgn);
- }
- } /* AdjustCursor */
-
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Draw the contents of the application window. This will be black and white on old
- machines, but color on color machines. At this point, the window’s visRgn
- is set to allow drawing only where it needs to be done. */
-
- void DrawWindow(window)
- WindowPtr window;
- {
- SetPort(window);
- EraseRect(&window->portRect); /* clear out any garbage that may linger */
-
- switch (gVideoPattern)
- {
- case iTestPattern:
- DrawTestPattern(window);
- break;
-
- case iColorBars:
- DrawColorBars(window);
- break;
-
- case iGrayScaleLD:
- DrawGrayScaleLD(window);
- break;
-
- case iGrayScaleDL:
- DrawGrayScaleDL(window);
- break;
-
- case iVLines:
- DrawVertLines(window);
- break;
-
- case iHLines:
- DrawHorzLines(window);
- break;
-
- case iLBurst:
- DrawLineBurst(window);
- break;
-
- case iRedScreen:
- DrawRedScreen(window);
- break;
-
- case iGreenScreen:
- DrawGreenScreen(window);
- break;
-
- case iBlueScreen:
- DrawBlueScreen(window);
- break;
-
- case iWhiteScreen:
- DrawWhiteScreen(window);
- break;
- }
- } /* DrawWindow */
-
-
-
-
-
-
- /*---------------------------------------------------------------------------------------*/
- /* Check to see if a given trap is implemented. This is only used by the Initialize
- routine in this program. The recommended approach to see if a trap is implemented
- is to see if the address of the trap routine is the same as the address of the
- Unimplemented trap. Needs to be called after call to SysEnvirons so that it can check
- if a ToolTrap is out of range of a pre-MacII ROM. */
-
- Boolean TrapAvailable(tNumber,tType)
- short tNumber;
- TrapType tType;
- {
- if ( ( tType == ToolTrap ) &&
- ( gMac.machineType > envMachUnknown ) &&
- ( gMac.machineType < envMacII ) )
- { /* it's a 512KE, Plus, or SE */
- tNumber = tNumber & 0x03FF;
- if ( tNumber > 0x01FF ) /* which means the tool traps */
- tNumber = _Unimplemented; /* only go to 0x01FF */
- }
- return NGetTrapAddress(tNumber, tType) != GetTrapAddress(_Unimplemented);
- } /* TrapAvailable */